import collections
import re
import tokenize
import operator
import string
import itertools
import simpleparse
from simpleparse.common import numbers, strings
from simpleparse.parser import Parser
from functools import partial


class JSONBase(collections.Mapping):
    pass

class JSONObject(JSONBase, dict):
    def __contains__(self, v):
        if v.startswith('$'):
            return contains(self, v)
        else:
            return dict.__contains__(self, v)

    def __setitem__(self, k, v):
        if k.startswith('$'):
            setitem(self, k, v)
        else:
            dict.__setitem__(self, k, v)

    def __getitem__(self, k):
        if k.startswith('$'):
            return getitem(self, k)
        else:
            return dict.__getitem__(self, k)

    #===========================================================================
    #                                API
    #===========================================================================
    #
    # As a container, dictionaries generalize lists. Hence, JSON container API 
    # follows more closely the API for python dicts than python lists.
    # One notable difference is that JSONContainerDicts keys must be strings.
    #
    def count(self, v):
        return self.values().count(v)

    def get(self, k, *args):
        if k.startswith('$'):
            getitem(self, k, *args)
        else:
            return dict.get(self, k, *args)

    def has_key(self, k):
        return k in self

    def has_value(self, v):
        return v in self.values()

    def index(self, v, *args):
        if args:
            keys = self.keys()
            args = map(keys.index, args)
            return self.obj.values().index(v, *args)
        else:
            return self.obj.values().index(v)

    def items(self):
        return self.obj.items()

    def iteritems(self):
        return self.obj.iteritems()

    def iterkeys(self):
        return self.obj.iterkeys()

    def itervalues(self):
        return self.obj.itervalues()

    def keys(self):
        return self.obj.keys()

    def pop(self, *args):
        return self.obj.pop(*args)

    def popitem(self):
        return self.obj.popitem()

    def setdefault(self, *args):
        # Assure that key is str/unicode
        if len(args) != 0:
            if not isinstance(args[0], Str):
                raise TypeError('keys must be strings, got %s' % type(args[0]))
        return self.obj.setdefault(*args)

    def update(self, dic):
        # Assure that all keys are str/unicode
        try:
            it = dict.keys()
        except AttributeError:
            it = (k for (k, v) in dic)
        for k in it:
            if not isinstance(k, Str):
                raise TypeError('keys must be strings, got %s' % type(args[0]))

        # Update dictionary
        return self.obj.update(dic)

    def values(self):
        return self.obj.values()


class Foo:
    #===========================================================================
    #                                API
    #===========================================================================
    #
    # As a container, dictionaries generalize lists. Hence, JSON container API 
    # follows more closely the API for python dicts than python lists.
    # One notable difference is that JSONContainerDicts keys must be strings.
    #

    def clear(self):
        return self.obj.clear()

    def copy(self):
        return self.obj.copy()

    def count(self, v):
        return self.values().count(v)

    def get(self, k, *args):
        return self.obj.get(k, *args)

    def has_key(self, k):
        return self.obj.has_key(k)

    def has_value(self, v):
        return v in self.values()

    def index(self, v, *args):
        if args:
            keys = self.keys()
            args = map(keys.index, args)
            return self.obj.values().index(v, *args)
        else:
            return self.obj.values().index(v)

    def items(self):
        return self.obj.items()

    def iteritems(self):
        return self.obj.iteritems()

    def iterkeys(self):
        return self.obj.iterkeys()

    def itervalues(self):
        return self.obj.itervalues()

    def keys(self):
        return self.obj.keys()

    def pop(self, *args):
        return self.obj.pop(*args)

    def popitem(self):
        return self.obj.popitem()

    def setdefault(self, *args):
        # Assure that key is str/unicode
        if len(args) != 0:
            if not isinstance(args[0], Str):
                raise TypeError('keys must be strings, got %s' % type(args[0]))
        return self.obj.setdefault(*args)

    def update(self, dic):
        # Assure that all keys are str/unicode
        try:
            it = dict.keys()
        except AttributeError:
            it = (k for (k, v) in dic)
        for k in it:
            if not isinstance(k, Str):
                raise TypeError('keys must be strings, got %s' % type(args[0]))

        # Update dictionary
        return self.obj.update(dic)

    def values(self):
        return self.obj.values()

#class JSONObject(dict, JSON):
#    pass
#
#class JSONContainerList(JSONContainer):
#    pass
#
#class JSONContainerAdaptor(JSONContainer):
#    pass
if __name__ == '__main__':
    from chips.debug import *

    qtest = { 'meta': { 'title': 'Foo', 'db_name': 'foobar' },
              'content': [ { 'type': 'text',
                             'text': 'some text' },
                           { 'type': 'multiple-choice',
                             'items': [ { 'text': 'Foo' },
                                        { 'text': 'Bar' } ] }]}

    import doctest
    doctest.testmod(optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
